import Axios, {
  type AxiosInstance,
  type AxiosRequestConfig,
  type CustomParamsSerializer
} from "axios";
import type {
  PureHttpError,
  RequestMethods,
  PureHttpResponse,
  PureHttpRequestConfig
} from "./types.d";
import { stringify } from "qs";
import NProgress from "../progress";
import { getToken, formatToken } from "@/utils/auth";
import { useUserStoreHook } from "@/store/modules/user";
import { useUserAuthStore } from "@/store/modules/userAuth";

// 相关配置请参考：www.axios-js.com/zh-cn/docs/#axios-request-config-1
const defaultConfig: AxiosRequestConfig = {
  // API基础地址 - 使用代理，开发环境会自动代理到后端
  baseURL: import.meta.env.DEV ? "" : "http://localhost:8848",
  // 请求超时时间
  timeout: 10000,
  headers: {
    Accept: "application/json, text/plain, */*",
    "Content-Type": "application/json",
    "X-Requested-With": "XMLHttpRequest"
  },
  // 数组格式参数序列化（https://github.com/axios/axios/issues/5142）
  paramsSerializer: {
    serialize: stringify as unknown as CustomParamsSerializer
  }
};

class PureHttp {
  constructor() {
    this.httpInterceptorsRequest();
    this.httpInterceptorsResponse();
  }

  /** `token`过期后，暂存待执行的请求 */
  private static requests = [];

  /** 防止重复刷新`token` */
  private static isRefreshing = false;

  /** 初始化配置对象 */
  private static initConfig: PureHttpRequestConfig = {};

  /** 保存当前`Axios`实例对象 */
  private static axiosInstance: AxiosInstance = Axios.create(defaultConfig);

  /** 重连原始请求 */
  private static retryOriginalRequest(config: PureHttpRequestConfig) {
    return new Promise(resolve => {
      PureHttp.requests.push((token: string) => {
        config.headers["Authorization"] = formatToken(token);
        resolve(config);
      });
    });
  }

  /** 请求拦截 */
  private httpInterceptorsRequest(): void {
    PureHttp.axiosInstance.interceptors.request.use(
      async (config: PureHttpRequestConfig): Promise<any> => {
        // 开启进度条动画
        NProgress.start();

        // 如果是FormData，删除Content-Type让浏览器自动设置
        if (config.data instanceof FormData) {
          if (
            config.headers &&
            config.headers["Content-Type"] === "application/json"
          ) {
            delete config.headers["Content-Type"];
          }
        }

        // 为公告管理相关的GET请求添加强制缓存控制，避免304 Not Modified
        if (
          config.method?.toLowerCase() === "get" &&
          config.url?.includes("/admin/announcements/")
        ) {
          config.headers = {
            ...config.headers,
            "Cache-Control": "no-cache, no-store, must-revalidate",
            Pragma: "no-cache",
            Expires: "0",
            "If-None-Match": "",
            "If-Modified-Since": ""
          };

          // 为URL添加时间戳参数避免缓存
          if (config.params) {
            config.params._t = Date.now();
          } else {
            config.params = { _t: Date.now() };
          }
        }

        // 优先判断post/get等方法是否传入回调，否则执行初始化设置等回调
        if (typeof config.beforeRequestCallback === "function") {
          config.beforeRequestCallback(config);
          return config;
        }
        if (PureHttp.initConfig.beforeRequestCallback) {
          PureHttp.initConfig.beforeRequestCallback(config);
          return config;
        }

        /** 请求白名单，放置一些不需要`token`的接口 */
        const whiteList = [
          // 管理端白名单
          "/auth/refresh",
          "/auth/login",
          "/auth/logout",
          // 用户端白名单
          "/user/auth/register",
          "/user/auth/login",
          "/user/auth/logout",
          "/user/auth/send-verification-code",
          "/user/auth/verify-email-code",
          "/user/auth/forgot-password",
          "/user/auth/validate-reset-token",
          "/user/auth/reset-password"
        ];

        /** 用户端白名单（GET请求）- 这些接口不需要登录即可访问 */
        const userWhiteList = [
          "/api/comments/article/", // 获取文章评论列表
          "/api/comments/{commentId}/replies", // 获取评论回复列表（会动态处理）
          "/api/comments/{commentId}/stats", // 获取评论统计信息（会动态处理）
          "/api/comments/{commentId}" // 获取评论详情（会动态处理）
        ];

        // 检查是否在白名单中
        const isInWhiteList = whiteList.some(url => config.url?.includes(url));

        // 检查用户端白名单（仅GET请求且未登录时）
        const isUserWhiteList =
          config.method?.toLowerCase() === "get" &&
          (userWhiteList.some(url => config.url?.includes(url)) ||
            /\/api\/comments\/\d+\/replies/.test(config.url || "") ||
            /\/api\/comments\/\d+\/stats/.test(config.url || "") ||
            /\/api\/comments\/\d+$/.test(config.url || ""));

        if (isInWhiteList) {
          return config;
        }

        // 判断接口类型并添加对应的Authorization请求头
        const isUserApi =
          config.url?.startsWith("/user") ||
          config.url?.startsWith("/api/user") ||
          config.url?.startsWith("/api/comments");
        const isAdminApi =
          config.url?.startsWith("/admin") || config.url?.startsWith("/auth");

        if (isUserApi) {
          // 处理用户端API
          const userAuthStore = useUserAuthStore();

          // 如果是用户端白名单的GET请求且未登录，直接放行
          if (isUserWhiteList && !userAuthStore.isLoggedIn) {
            console.log(`📖 用户端API [${config.url}] 免登录访问 (GET请求)`);
            return config;
          }

          if (userAuthStore.isLoggedIn) {
            // 检查token是否即将过期
            if (userAuthStore.isTokenExpiringSoon) {
              try {
                await userAuthStore.refreshToken();
              } catch (error) {
                console.error("用户端Token刷新失败:", error);
                // Token刷新失败，清除用户信息
                userAuthStore.clearUserInfo();
                return Promise.reject(new Error("用户认证已过期，请重新登录"));
              }
            }
            config.headers["Authorization"] = formatToken(userAuthStore.token);
            console.log(
              `🔐 用户端API [${config.url}] 添加Authorization请求头 (已登录)`
            );
          } else {
            // 即使未登录，也尝试添加token（如果存在的话）
            if (userAuthStore.token) {
              config.headers["Authorization"] = formatToken(
                userAuthStore.token
              );
              console.log(
                `🔐 用户端API [${config.url}] 添加Authorization请求头 (未登录但有token)`
              );
            } else {
              console.log(`⚠️ 用户端API [${config.url}] 无token可用`);
            }
          }
          return config;
        } else if (isAdminApi) {
          // 处理管理端API
          return new Promise(resolve => {
            const data = getToken();
            if (data) {
              const now = new Date().getTime();
              const expired = parseInt(data.expires) - now <= 0;
              if (expired) {
                if (!PureHttp.isRefreshing) {
                  PureHttp.isRefreshing = true;
                  // token过期刷新
                  useUserStoreHook()
                    .handRefreshToken()
                    .then(res => {
                      const token = res.data?.token;
                      config.headers["Authorization"] = formatToken(token);
                      PureHttp.requests.forEach(cb => cb(token));
                      PureHttp.requests = [];
                    })
                    .finally(() => {
                      PureHttp.isRefreshing = false;
                    });
                }
                resolve(PureHttp.retryOriginalRequest(config));
              } else {
                config.headers["Authorization"] = formatToken(
                  data.token || data.accessToken
                );
                resolve(config);
              }
            } else {
              resolve(config);
            }
          });
        } else {
          // 其他API（如通用API）- 优先尝试用户端认证，如果没有则尝试管理端认证
          const userAuthStore = useUserAuthStore();
          if (userAuthStore.isLoggedIn) {
            // 使用用户端认证
            if (userAuthStore.isTokenExpiringSoon) {
              try {
                await userAuthStore.refreshToken();
              } catch (error) {
                console.error("用户端Token刷新失败:", error);
                userAuthStore.clearUserInfo();
                return Promise.reject(new Error("用户认证已过期，请重新登录"));
              }
            }
            config.headers["Authorization"] = formatToken(userAuthStore.token);
            console.log(
              `🔐 通用API [${config.url}] 添加用户端Authorization请求头 (已登录)`
            );
            return config;
          } else if (userAuthStore.token) {
            // 即使未登录，也尝试添加用户端token（如果存在的话）
            config.headers["Authorization"] = formatToken(userAuthStore.token);
            console.log(
              `🔐 通用API [${config.url}] 添加用户端Authorization请求头 (未登录但有token)`
            );
            return config;
          } else {
            // 尝试管理端认证
            const data = getToken();
            if (data) {
              const now = new Date().getTime();
              const expired = parseInt(data.expires) - now <= 0;
              if (!expired) {
                config.headers["Authorization"] = formatToken(
                  data.token || data.accessToken
                );
                console.log(
                  `🔐 通用API [${config.url}] 添加管理端Authorization请求头`
                );
              } else {
                console.log(`⚠️ 通用API [${config.url}] 管理端token已过期`);
              }
            } else {
              console.log(`⚠️ 通用API [${config.url}] 无任何token可用`);
            }
            return config;
          }
        }
      },
      error => {
        return Promise.reject(error);
      }
    );
  }

  /** 响应拦截 */
  private httpInterceptorsResponse(): void {
    const instance = PureHttp.axiosInstance;
    instance.interceptors.response.use(
      (response: PureHttpResponse) => {
        const $config = response.config;
        // 关闭进度条动画
        NProgress.done();
        // 优先判断post/get等方法是否传入回调，否则执行初始化设置等回调
        if (typeof $config.beforeResponseCallback === "function") {
          $config.beforeResponseCallback(response);
          return response.data;
        }
        if (PureHttp.initConfig.beforeResponseCallback) {
          PureHttp.initConfig.beforeResponseCallback(response);
          return response.data;
        }
        return response.data;
      },
      (error: PureHttpError) => {
        const $error = error;
        $error.isCancelRequest = Axios.isCancel($error);
        // 关闭进度条动画
        NProgress.done();
        // 所有的响应异常 区分来源为取消请求/非取消请求
        return Promise.reject($error);
      }
    );
  }

  /** 通用请求工具函数 */
  public request<T>(
    method: RequestMethods,
    url: string,
    param?: AxiosRequestConfig,
    axiosConfig?: PureHttpRequestConfig
  ): Promise<T> {
    const config = {
      method,
      url,
      ...param,
      ...axiosConfig
    } as PureHttpRequestConfig;

    // 单独处理自定义请求/响应回调
    return new Promise((resolve, reject) => {
      PureHttp.axiosInstance
        .request(config)
        .then((response: undefined) => {
          resolve(response);
        })
        .catch(error => {
          reject(error);
        });
    });
  }

  /** 单独抽离的`post`工具函数 */
  public post<T, P>(
    url: string,
    params?: AxiosRequestConfig<P>,
    config?: PureHttpRequestConfig
  ): Promise<T> {
    return this.request<T>("post", url, params, config);
  }

  /** 单独抽离的`get`工具函数 */
  public get<T, P>(
    url: string,
    params?: AxiosRequestConfig<P>,
    config?: PureHttpRequestConfig
  ): Promise<T> {
    return this.request<T>("get", url, params, config);
  }
}

export const http = new PureHttp();
